package com.resou.reader.utils.diskcache;


import com.resou.reader.utils.diskcache.lru.DiskLruCache;
import com.resou.reader.utils.diskcache.lru.Util;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * Created by Castiel on 2018/5/7.
 */

public class DiskCacheWrapper {

    static final int APP_VERSION = 1;
    static final int VALUE_COUNT = 1;

    /**
     * 300MB disk cache
     */
    static int DEFAULT_DISK_CACHE_SIZE = 300 * 1024 * 1024;

    private SafeKeyGenerator mKeyGenerator;
    private DiskLruCache mDiskLruCache;
    private File mDirectory;
    private long mMaxSize = DEFAULT_DISK_CACHE_SIZE;

    private static DiskCacheWrapper wrapper;

    public static DiskCacheWrapper get(File directory, long maxSize) {
        if (wrapper == null) {
            synchronized (DiskCacheWrapper.class) {
                if (wrapper == null) {
                    wrapper = new DiskCacheWrapper(directory, maxSize);
                }
            }
        }
        return wrapper;
    }

    public static DiskCacheWrapper get(File directory) {
        return get(directory, DEFAULT_DISK_CACHE_SIZE);
    }

    private DiskCacheWrapper(File directory, long maxSize) {
        this.mDirectory = directory;
        this.mMaxSize = maxSize;
        this.mKeyGenerator = new SafeKeyGenerator();
    }

    private synchronized DiskLruCache getDiskCache() throws IOException {
        if (mDiskLruCache == null) {
            mDiskLruCache = DiskLruCache.open(mDirectory, APP_VERSION, VALUE_COUNT, mMaxSize);
        }
        return mDiskLruCache;
    }

    /**
     * save value without expires
     *
     * @param key
     * @param value
     */
    public void put(String key, String value) {
        put(key, value, -1);
    }

    /**
     * save value with expires
     *
     * @param key
     * @param value
     * @param expires
     */
    public void put(String key, String value, long expires) {
        String encodeKey = mKeyGenerator.getSafeKey(key);
        try {
            DiskLruCache.Editor editor = getDiskCache().edit(encodeKey);
            editor.set(0, value);
            if (expires > 0) {
                editor.setExpires(expires);
            }
            editor.commit();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * save value without expires
     * Don't forget call close()!
     *
     * @param key
     */
    public DiskLruCache.Editor getEditor(String key) {
        return getEditor(key, -1);
    }

    /**
     * save value without expires
     * Don't forget call close()!
     *
     * @param key
     * @param expires
     */
    public DiskLruCache.Editor getEditor(String key, long expires) {
        String encodeKey = mKeyGenerator.getSafeKey(key);
        try {
            DiskLruCache.Editor editor = getDiskCache().edit(encodeKey);
            if (expires > 0) {
                editor.setExpires(expires);
            }
            return editor;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get value
     * if cache item not exist or expired,it will return null.
     *
     * @param key
     * @return
     */
    public String get(String key) {
        String encodeKey = mKeyGenerator.getSafeKey(key);
        DiskLruCache.Snapshot snapshot = null;
        try {
            snapshot = getDiskCache().get(encodeKey);
            if (snapshot != null) {
                return snapshot.getString(0);
            } else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (snapshot != null) {
                snapshot.close();
            }
        }
        return null;
    }

    /**
     * get input stream
     * Don't forget call close()!
     *
     * @param key
     * @return
     */
    public InputStream getInputStream(String key) {
        String encodeKey = mKeyGenerator.getSafeKey(key);
        DiskLruCache.Snapshot snapshot = null;
        try {
            snapshot = getDiskCache().get(encodeKey);
            if (snapshot != null) {
                return snapshot.getInputStream(0);
            } else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * close in/out io stream
     *
     * @param stream
     */
    public void close(Closeable stream) {
        Util.closeQuietly(stream);
    }

    public void closeCache() {
        try {
            DiskLruCache cache = getDiskCache();
            cache.close();
            wrapper = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void remove(String key) {
        String encodeKey = mKeyGenerator.getSafeKey(key);
        try {
            DiskLruCache cache = getDiskCache();
            cache.remove(encodeKey);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * delete all cache
     */
    public void clearCache() {
        try {
            DiskLruCache cache = getDiskCache();
            cache.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
